/*
 * Galaxium Messenger
 * Copyright (C) 2005-2007 Ben Motmans <ben.motmans@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Collections.Generic;

using Anculus.Core;
using Galaxium.Core;

namespace Galaxium.Gui
{
	public class IconManager<IconType>
	{
		public const string DefaultTheme = "default";
		public const string AllThemes = "*";

		private string _theme = null;
		
		private Dictionary<string, IconTheme<IconType>> _themes;
		private IIconThemeLoader<IconType> _themeLoader;
		private List<IIconSize> _iconSizes;

		private RescaleIconTypeHandler<IconType> _rescaleHandler;

		public IconManager (IIconThemeLoader<IconType> themeLoader, RescaleIconTypeHandler<IconType> rescaleHandler)
		{
			ThrowUtility.ThrowIfNull ("themeLoader", themeLoader);
			ThrowUtility.ThrowIfNull ("rescaleHandler", rescaleHandler);

			_rescaleHandler = rescaleHandler;
			_themeLoader = themeLoader;
			_iconSizes = new List<IIconSize> ();
			RegisterIconSize (IconSizes.Other);

			_themes = new Dictionary<string, IconTheme<IconType>> ();
			_themes.Add (DefaultTheme, new IconTheme<IconType> (rescaleHandler));
		}

		public string Theme
		{
			get { return _theme; }
			set
			{
				ThrowUtility.ThrowIfEmpty ("Theme", value);

				if (value == _theme)
					return;

				if (!String.IsNullOrEmpty (_theme))
					UnloadTheme (_theme);
				
				_theme = value;
				
				LoadTheme (value);
			}
		}

		public void RegisterDefaultIconSizes ()
		{
			RegisterIconSize (IconSizes.Tiny);
			RegisterIconSize (IconSizes.Small);
			RegisterIconSize (IconSizes.MediumSmall);
			RegisterIconSize (IconSizes.Medium);
			RegisterIconSize (IconSizes.Large);
			RegisterIconSize (IconSizes.ExtraLarge);
			RegisterIconSize (IconSizes.Huge);
			RegisterIconSize (IconSizes.Gigantic);
		}

		public void RegisterIconSize (IIconSize iconSize)
		{
			ThrowUtility.ThrowIfNull ("iconSize", iconSize);

			if (DuplicateIconSize (iconSize))
				Log.Warn("Duplicate icon size. (identifier: {0})", iconSize.Identifier);
			else
				_iconSizes.Add(iconSize);
		}

		private bool DuplicateIconSize (IIconSize iconSize)
		{
			foreach (IIconSize size in _iconSizes) {
				if (size == iconSize || size.Size == iconSize.Size
					|| String.Compare (size.Identifier, iconSize.Identifier, true) == 0
					)
					return true;
			}
			return false;
		}

		public IIconSize GetIconSize (int size)
		{
			foreach (IIconSize iconSize in _iconSizes)
				if (iconSize.Size == size)
					return iconSize;
			return IconSizes.Other;
		}

		public IIconSize GetIconSize (string identifier)
		{
			ThrowUtility.ThrowIfEmpty ("identifier", identifier);

			foreach (IIconSize iconSize in _iconSizes)
				if (iconSize.Identifier == identifier)
					return iconSize;
			return IconSizes.Other;
		}

		public IIconSize ParseIconSize (string identifier)
		{
			ThrowUtility.ThrowIfEmpty ("identifier", identifier);

			foreach (IIconSize size in _iconSizes) {
				if (size.Size.ToString () == identifier
					|| String.Compare (size.Identifier, identifier, true) == 0
					)
					return size;
			}
			return IconSizes.Other;
		}

		public IconType GetIcon (string name)
		{
			return GetIcon (_theme, name, IconSizes.Other);
		}

		public IconType GetIcon (string name, IIconSize iconSize)
		{
			return GetIcon (_theme, name, iconSize);
		}

		public IconType GetIcon (string theme, string name)
		{
			return GetIcon (theme, name, IconSizes.Other);
		}

		public IconType GetIcon (string theme, string name, IIconSize iconSize)
		{
			ThrowUtility.ThrowIfEmpty ("theme", theme);
			ThrowUtility.ThrowIfEmpty ("name", name);
			
			if (_themes.ContainsKey (theme))
			{
				return _themes[theme].GetIcon (name, iconSize);
			}
			else
				Log.Error("Icon theme not found: "+theme);
			
			return default (IconType);
		}

		public void AddIcon (string name, IconType icon)
		{
			AddIcon (DefaultTheme, name, IconSizes.Other, icon);
		}

		public void AddIcon (string theme, string name, IconType icon)
		{
			AddIcon (theme, name, IconSizes.Other, icon);
		}

		public void AddIcon (string theme, string name, IIconSize iconSize, IconType icon)
		{
			ThrowUtility.ThrowIfEmpty ("theme", theme);
			ThrowUtility.ThrowIfEmpty ("name", name);

			AddTheme (theme);
			_themes[theme].AddIcon (name, iconSize, icon);
		}

		public bool ThemeExists (string theme)
		{
			ThrowUtility.ThrowIfEmpty ("theme", theme);

			return _themes.ContainsKey (theme);
		}
		
		internal void AddTheme (string theme)
		{
			ThrowUtility.ThrowIfEmpty ("theme", theme);
		
			if (!_themes.ContainsKey (theme))
				_themes.Add (theme, new IconTheme<IconType> (_rescaleHandler));
		}

		public bool IconExists (string theme, string name)
		{
			ThrowUtility.ThrowIfEmpty ("theme", theme);
			ThrowUtility.ThrowIfEmpty ("name", name);

			if (_themes.ContainsKey (theme))
				return _themes[theme].IconExists (name);
			return false;
		}

		public bool IconExists (string name)
		{
			ThrowUtility.ThrowIfEmpty ("name", name);

			return IconExists (DefaultTheme, name);
		}

		public IEnumerable<string> Themes
		{
			get { return _themes.Keys; }
		}

		public IEnumerable<string> GetIconNames (string theme)
		{
			ThrowUtility.ThrowIfNull ("theme", theme);

			if (_themes.ContainsKey (theme))
				return _themes[theme].Names;
			return null;
		}

		public void UnloadTheme (string theme)
		{
			ThrowUtility.ThrowIfNull ("theme", theme);

			if (theme != DefaultTheme && _themes.ContainsKey (theme))
				_themes.Remove (theme);
		}

		public void LoadTheme (string theme)
		{
			ThrowUtility.ThrowIfNull ("theme", theme);
			
			foreach (IconExtension<IconType> ext in _themeLoader.LoadIcons (theme))
			{
				if (ext.Theme == null || ext.Resource == null)
				{
					Log.Warn ("Invalid icon '{0}' ('{1}' '{2}')", ext.Identifier, ext.Theme, ext.Resource);
					continue;
				}
				
				AddTheme (theme);
				_themes[theme].AddIcon (ext, false);
			}
		}
	}
}
